﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
using System.Windows.Forms;
using NS_Client.Data;

namespace NS_Client
{
    /// <summary>Base Class in Hierarchy of Controllers</summary>
    public abstract class Controller
    {
        /// <summary>Terminates the Application if no forms are open</summary>
        public void CheckShouldAppClose()
        {
            if (Application.OpenForms.Count == 0)
                Application.Exit();
        }
    }

    /// <summary>Controlls Applications flow of currently displayed views</summary>
    public class ApplicationController : Controller, IObserver
    {
        //private static readonly ApplicationController _instance = new ApplicationController();

        //public static ApplicationController GetInstance()
        //{
        //     return _instance; 
        //}

        /// <summary>SessionModel associated with this Application instance</summary>
        protected SessionModel ApplicationSession;
        /// <summary>CommsLogic associated with this Application instance</summary>
        protected CommsLogic ApplicationCommsLogic;

        LoginController LoginViewControl;
        MainController MainViewControl;        

        public ApplicationController()
        {
            ApplicationSession = new SessionModel();
            ApplicationCommsLogic = new CommsLogic(ref ApplicationSession);

            LoginViewControl = new LoginController(ref ApplicationSession, ref ApplicationCommsLogic);
            MainViewControl = new MainController(ref ApplicationSession, ref ApplicationCommsLogic);

            ApplicationSession.Register(this);
            this.notify(ApplicationSession);
        }

        /// <summary>Displays and closes appropriate forms</summary>
        /// <param name="Data">The data to determine how to react to notification</param>
        public void notify(object Data)
        {
            // If Logged In & MainView is not visible
            if (ApplicationSession.LoggedIn == true && MainViewControl.IsViewVisible == false)
            {
                // Show MainView, close LoginView
                MainViewControl.ShowView();
                LoginViewControl.CloseView();
            }

            // If not logged in & LoginView is not visible
            if (ApplicationSession.LoggedIn == false && LoginViewControl.IsViewVisible == false)
            {
                // Show LoginView, close MainView
                LoginViewControl.ShowView();
                MainViewControl.CloseView();
            }
        }


    }

    /// <summary>Abstract Type of Controller grouping functionality specific to a Controller with a Form</summary>
    public abstract class ViewController : Controller
    {
        /// <summary>SessionModel reference associated with a parent ApplicationViewController instance</summary>
        protected SessionModel SessionM;
        /// <summary>CommsLogic reference associated with a parent ApplicationViewController instance</summary>
        protected CommsLogic CommunicationsLogic;

        /// <summary>The UI form associated with this ViewController instance</summary>
        protected NS_UI ChildView;

        /// <summary>base Constructer called when a child-type is instantiated</summary>
        /// <param name="Communicationslogic">Reference to a SessionModel shared between ViewControllers</param>
        /// <param name="ModelSession">Reference to a CommsLogic shared between ViewControllers</param>
        public ViewController(ref SessionModel ModelSession, ref CommsLogic Communicationslogic)
        {
            SessionM = ModelSession;
            CommunicationsLogic = Communicationslogic;
        }

        /// <summary>Returns if the form associated with the current ViewController is visible</summary>
        public virtual bool IsViewVisible
        {
            get
            {
                if (ChildView == null) return false;

                return ChildView.Visible;
            }
        }

        /// <summary>Shows the form associated with the current ViewController</summary>
        public virtual void ShowView()
        {
            ChildView.SetListener(this);
            ChildView.Show();
            
            SessionM.Register(ChildView);

            ChildView.notify(SessionM);
        }

        /// <summary>Closes the form associated with the current ViewController</summary>
        public virtual void CloseView()
        {
            if (IsViewVisible)
                SessionM.UnRegister(ChildView);
            try
            {
                ChildView.Dispose();
            }
            catch (Exception ex)
            {
                // System.Diagnostics.Debug.WriteLine(ex);
            }

            base.CheckShouldAppClose();
        }
    }

    /// <summary>Controlls how to handle the LoginForm view and events</summary>
    public class LoginController : ViewController
    {
        public LoginController(ref SessionModel ModelSession, ref CommsLogic Communicationslogic)
            : base(ref ModelSession, ref Communicationslogic) { }

        /// <summary>Shows the view associated with this LoginViewController instance</summary>
        public override void ShowView()
        {
            ChildView = new LoginForm();
            base.ShowView();
        }

        /// <summary>Sends login attempt to server and updates model according to response</summary>
        public void LogIn(string username, string pass)
        {
            SessionM.Username = username;

            string ParsedMessage = Parser.Build_LogIn(SessionM.Username, pass);
            CommunicationsLogic.SendProtocolMessage(ParsedMessage);
        }
    }

    /// <summary>Controlls how to handle the MainForm view and events</summary>
    public class MainController : ViewController
    {
        public MainController(ref SessionModel ModelSession, ref CommsLogic Communicationslogic)
            : base(ref ModelSession, ref Communicationslogic) { }

        /// <summary>Shows the view associated with this MainViewController instance</summary>
        public override void ShowView()
        {
            GetContentList();
            GetUserData();
            ChildView = new MainForm();
            base.ShowView();
        }

        /// <summary>Updates model to logged out status</summary>
        public void LogOut()
        {
            SessionM.LoggedIn = false;
        }

        public void GetUserData()
        {
            string GetUserData_ProtocolStr = Parser.Build_GetUserData(SessionM.SessionID, true, SessionM.Username);
            CommunicationsLogic.SendProtocolMessage(GetUserData_ProtocolStr);
        }

        public void Download(string softwareID)
        {
            string RequestDownloadContentItem_ProtocolMessage = Parser.Build_RequestDownload(softwareID, SessionM.SessionID);
            CommunicationsLogic.SendProtocolMessage(RequestDownloadContentItem_ProtocolMessage);
        }

        public void GetContentList()
        {
            string QueryContentList_ProtocolMessage = Parser.Build_QueryContentList(SessionM.SessionID);
            CommunicationsLogic.SendProtocolMessage(QueryContentList_ProtocolMessage);
        }

        public void CreateContent(string name, string description, string file)
        {
            string CreateSoftware_ProtocolStr = Parser.Build_CreateContentDescription(SessionM.SessionID, name, description);
            CommunicationsLogic.CreateContent(CreateSoftware_ProtocolStr, file);
        }

        public void SendChatMsg(string message)
        {
            string ChatMessage_ProtocolStr = Parser.Build_ChatMessage(SessionM.SessionID, message);
            CommunicationsLogic.SendProtocolMessage(ChatMessage_ProtocolStr);
        }

        public void PollChat()
        {
            string ChatLog_ProtocolStr = Parser.Build_PollChat(SessionM.SessionID);
            CommunicationsLogic.SendProtocolMessage(ChatLog_ProtocolStr);
        }
        
    }
}